package com.pll.controller.admin.commodity.redislogic;

import com.pll.controller.admin.commodity.vo.CommodityPaginationVO;
import com.pll.controller.admin.commodity.vo.ProductInformationVO;
import com.pll.pojo.Goods;
import com.pll.pojo.GoodsType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @className: GoodsRedisRepository
 * @author: XR_Z
 * @date: 2025/6/17 12:59
 * @Version: 1.0
 * @description: 商品及商品分类Redis操作仓库类，实现数据存储、多条件连表查询（含全量、总条数统计）
 */
@Repository
public class GoodsRedisRepository {

    // Redis Key 前缀定义
    private static final String GOODS_KEY_PREFIX = "goods:";
    private static final String GOODS_TYPE_KEY_PREFIX = "goods_type:";
    private static final String GOODS_BY_TYPE_KEY_PREFIX = "goods:by_type:";
    private static final String GOODS_NAME_INDEX_KEY_PREFIX = "goods:index:name:";
    private static final String GOODS_STATUS_INDEX_KEY_PREFIX = "goods:index:status:";
    private static final String GOODS_SALE_STATUS_INDEX_KEY_PREFIX = "goods:index:sale_status:";
    private static final String GOODS_TYPE_NAME_INDEX_KEY_PREFIX = "goods_type:index:name:";
    private static final String GOODS_SORT_KEY = "goods:sort:create_time";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // ====================== 数据存储方法 ======================
    /**
     * 保存商品信息到 Redis，同时维护各类索引
     */
    public void saveGoods(Goods goods) {
        String goodsKey = GOODS_KEY_PREFIX + goods.getGoodId();
        redisTemplate.opsForHash().putAll(goodsKey, convertGoodsToMap(goods));

        // 维护商品名称索引
        String nameIndexKey = GOODS_NAME_INDEX_KEY_PREFIX + goods.getGoodName();
        redisTemplate.opsForSet().add(nameIndexKey, goods.getGoodId());

        // 维护商品状态索引
        String statusIndexKey = GOODS_STATUS_INDEX_KEY_PREFIX + goods.getGoodStatus();
        redisTemplate.opsForSet().add(statusIndexKey, goods.getGoodId());

        // 维护商品销售方式索引
        String saleStatusIndexKey = GOODS_SALE_STATUS_INDEX_KEY_PREFIX + goods.getGoodSaleStatus();
        redisTemplate.opsForSet().add(saleStatusIndexKey, goods.getGoodId());

        // 维护商品分类关联
        String goodsByTypeKey = GOODS_BY_TYPE_KEY_PREFIX + goods.getGoodTypeId();
        redisTemplate.opsForSet().add(goodsByTypeKey, goods.getGoodId());

        // 维护排序的 Sorted Set（按时间）
        redisTemplate.opsForZSet().add(GOODS_SORT_KEY, goods.getGoodId(), LocalDateTime.now().toEpochSecond(java.time.ZoneOffset.UTC));
    }

    /**
     * 保存商品分类信息到 Redis，同时维护分类名称索引
     */
    public void saveGoodsType(GoodsType goodsType) {
        String goodsTypeKey = GOODS_TYPE_KEY_PREFIX + goodsType.getGoodTypeId();
        redisTemplate.opsForHash().putAll(goodsTypeKey, convertGoodsTypeToMap(goodsType));

        // 维护商品分类名称索引
        String typeNameIndexKey = GOODS_TYPE_NAME_INDEX_KEY_PREFIX + goodsType.getGoodTypeName();
        redisTemplate.opsForSet().add(typeNameIndexKey, goodsType.getGoodTypeId());
    }

    // ====================== 核心查询方法 ======================
    /**
     * 多条件连表查询，返回包含【总条数】和【当前页商品列表】的结果
     */
    public HashMap<String, Object> queryGoods(CommodityPaginationVO vo) {
        HashMap<String, Object> responseHash = new HashMap<>();
        // 当前所有redis中的商品数量（满足条件的总条数）
        long total;
        Set<Integer> resultGoodIds = new HashSet<>();

        // 判断是否所有查询条件都为空（空则查全量）
        boolean allConditionsEmpty = isAllConditionsEmpty(vo);
        if (allConditionsEmpty) {
            // 全量查询：从 Sorted Set 拿数据（推荐，比 keys 高效）
            Set<Object> allGoodIds = redisTemplate.opsForZSet().range(GOODS_SORT_KEY, 0, -1);
            if (allGoodIds != null && !allGoodIds.isEmpty()) {
                resultGoodIds.addAll(convertToIntegerSet(allGoodIds));
            }
        } else {
            // 条件过滤查询：依次处理各条件
            filterByGoodName(vo, resultGoodIds);
            filterByGoodStatus(vo, resultGoodIds);
            filterBySaleStatus(vo, resultGoodIds);
            filterByGoodTypeName(vo, resultGoodIds);
            filterByTimeRange(vo, resultGoodIds);
        }

        // 获取满足条件的商品总条数
        total = resultGoodIds.size();

        // 分页处理
        List<Integer> pageGoodIds = paginate(resultGoodIds, vo.getPageNum(), vo.getPageSize());

        // 查询商品详情并封装结果
        List<Goods> goodsList = queryGoodsDetails(pageGoodIds);
        responseHash.put("goods", goodsList);
        // 将总条数放入返回的 HashMap 中
        responseHash.put("total", total);

        // 封装最终返回结果
        return responseHash;
    }

    // ====================== 工具方法（条件过滤、转换、分页等） ======================
    /**
     * 判断 CommodityPaginationVO 的所有查询条件是否为空
     */
    private boolean isAllConditionsEmpty(CommodityPaginationVO vo) {
        return (vo.getGoodName() == null || vo.getGoodName().trim().isEmpty()) &&
                vo.getGoodSpecification() == null &&
                vo.getGoodUnit() == null &&
                (vo.getGoodTypeName() == null || vo.getGoodTypeName().trim().isEmpty()) &&
                (vo.getStartTime() == null || vo.getEndTime() == null);
    }

    /**
     * 按商品名称过滤
     */
    private void filterByGoodName(CommodityPaginationVO vo, Set<Integer> resultGoodIds) {
        if (vo.getGoodName() != null && !vo.getGoodName().trim().isEmpty()) {
            String nameIndexKey = GOODS_NAME_INDEX_KEY_PREFIX + vo.getGoodName();
            Set<Object> ids = redisTemplate.opsForSet().members(nameIndexKey);
            if (ids != null) {
                resultGoodIds.addAll(convertToIntegerSet(ids));
            }
        }
    }

    /**
     * 按商品状态过滤
     */
    private void filterByGoodStatus(CommodityPaginationVO vo, Set<Integer> resultGoodIds) {
        if (vo.getGoodSpecification() != null) {
            String statusIndexKey = GOODS_STATUS_INDEX_KEY_PREFIX + vo.getGoodSpecification();
            Set<Object> ids = redisTemplate.opsForSet().members(statusIndexKey);
            if (ids != null) {
                Set<Integer> intIds = convertToIntegerSet(ids);
                if (resultGoodIds.isEmpty()) {
                    resultGoodIds.addAll(intIds);
                } else {
                    resultGoodIds.retainAll(intIds);
                }
            }
        }
    }

    /**
     * 按销售方式过滤
     */
    private void filterBySaleStatus(CommodityPaginationVO vo, Set<Integer> resultGoodIds) {
        if (vo.getGoodUnit() != null) {
            String saleStatusIndexKey = GOODS_SALE_STATUS_INDEX_KEY_PREFIX + vo.getGoodUnit();
            Set<Object> ids = redisTemplate.opsForSet().members(saleStatusIndexKey);
            if (ids != null) {
                Set<Integer> intIds = convertToIntegerSet(ids);
                if (resultGoodIds.isEmpty()) {
                    resultGoodIds.addAll(intIds);
                } else {
                    resultGoodIds.retainAll(intIds);
                }
            }
        }
    }

    /**
     * 按商品分类名称过滤
     */
    private void filterByGoodTypeName(CommodityPaginationVO vo, Set<Integer> resultGoodIds) {
        if (vo.getGoodTypeName() != null && !vo.getGoodTypeName().trim().isEmpty()) {
            String typeNameIndexKey = GOODS_TYPE_NAME_INDEX_KEY_PREFIX + vo.getGoodTypeName();
            Set<Object> typeIds = redisTemplate.opsForSet().members(typeNameIndexKey);
            if (typeIds != null) {
                Set<Integer> intTypeIds = convertToIntegerSet(typeIds);
                Set<Integer> tempGoodIds = new HashSet<>();
                for (Integer typeId : intTypeIds) {
                    String goodsByTypeKey = GOODS_BY_TYPE_KEY_PREFIX + typeId;
                    Set<Object> ids = redisTemplate.opsForSet().members(goodsByTypeKey);
                    if (ids != null) {
                        tempGoodIds.addAll(convertToIntegerSet(ids));
                    }
                }
                if (resultGoodIds.isEmpty()) {
                    resultGoodIds.addAll(tempGoodIds);
                } else {
                    resultGoodIds.retainAll(tempGoodIds);
                }
            }
        }
    }

    /**
     * 按时间范围过滤
     */
    private void filterByTimeRange(CommodityPaginationVO vo, Set<Integer> resultGoodIds) {
        if (vo.getStartTime() != null && vo.getEndTime() != null) {
            long start = vo.getStartTime().toEpochSecond(java.time.ZoneOffset.UTC);
            long end = vo.getEndTime().toEpochSecond(java.time.ZoneOffset.UTC);
            Set<Object> ids = redisTemplate.opsForZSet().rangeByScore(GOODS_SORT_KEY, start, end);
            if (ids != null) {
                Set<Integer> timeFilteredIds = convertToIntegerSet(ids);
                if (resultGoodIds.isEmpty()) {
                    resultGoodIds.addAll(timeFilteredIds);
                } else {
                    resultGoodIds.retainAll(timeFilteredIds);
                }
            }
        }
    }

    /**
     * 分页处理：从结果集中截取当前页 ID
     */
    private List<Integer> paginate(Set<Integer> goodIds, int pageNum, int pageSize) {
        List<Integer> sortedGoodIds = new ArrayList<>(goodIds);
        sortedGoodIds.sort(Comparator.comparingInt(Integer::intValue));
        int offset = (pageNum - 1) * pageSize;
        return sortedGoodIds.stream()
                .skip(offset)
                .limit(pageSize)
                .collect(Collectors.toList());
    }

    public void deleteGoodsById(Integer goodId) {

        // 开启Redis事务（保证操作原子性）
        redisTemplate.execute((RedisCallback<Object>) connection -> {
            connection.multi();

            // 1. 删除商品主数据
            String goodsKey = GOODS_KEY_PREFIX + goodId;
            connection.del(goodsKey.getBytes());

            // 2. 获取商品信息（用于删除索引）
            Map<Object, Object> goodsMap = redisTemplate.opsForHash().entries(goodsKey);
            if (goodsMap.isEmpty()) {
                connection.exec(); // 无数据则直接执行事务
                return null;
            }

            Goods goods = convertMapToGoods(goodsMap);

            // 3. 删除商品名称索引
            String nameIndexKey = GOODS_NAME_INDEX_KEY_PREFIX + goods.getGoodName();
            connection.sRem(nameIndexKey.getBytes(), String.valueOf(goodId).getBytes());

            // 4. 删除商品状态索引
            String statusIndexKey = GOODS_STATUS_INDEX_KEY_PREFIX + goods.getGoodStatus();
            connection.sRem(statusIndexKey.getBytes(), String.valueOf(goodId).getBytes());

            // 5. 删除商品销售方式索引
            String saleStatusIndexKey = GOODS_SALE_STATUS_INDEX_KEY_PREFIX + goods.getGoodSaleStatus();
            connection.sRem(saleStatusIndexKey.getBytes(), String.valueOf(goodId).getBytes());

            // 6. 删除商品分类关联
            String goodsByTypeKey = GOODS_BY_TYPE_KEY_PREFIX + goods.getGoodTypeId();
            connection.sRem(goodsByTypeKey.getBytes(), String.valueOf(goodId).getBytes());

            // 7. 删除排序索引
            connection.zRem(GOODS_SORT_KEY.getBytes(), String.valueOf(goodId).getBytes());

            return connection.exec();
        });
    }

    /**
     * 批量删除商品（物理删除，同时删除相关索引）
     */
    public void batchDeleteGoods(List<Integer> goodIds) {
        if (goodIds == null || goodIds.isEmpty()) {
            return;
        }

        // 开启Redis事务
        redisTemplate.execute((RedisCallback<Object>) connection -> {
            connection.multi();

            for (Integer goodId : goodIds) {
                // 1. 删除商品主数据
                String goodsKey = GOODS_KEY_PREFIX + goodId;
                connection.del(goodsKey.getBytes());

                // 2. 获取商品信息（用于删除索引）
                Map<Object, Object> goodsMap = redisTemplate.opsForHash().entries(goodsKey);
                if (goodsMap.isEmpty()) {
                    continue; // 无数据则跳过
                }

                Goods goods = convertMapToGoods(goodsMap);

                // 3. 删除商品名称索引
                String nameIndexKey = GOODS_NAME_INDEX_KEY_PREFIX + goods.getGoodName();
                connection.sRem(nameIndexKey.getBytes(), String.valueOf(goodId).getBytes());

                // 4. 删除商品状态索引
                String statusIndexKey = GOODS_STATUS_INDEX_KEY_PREFIX + goods.getGoodStatus();
                connection.sRem(statusIndexKey.getBytes(), String.valueOf(goodId).getBytes());

                // 5. 删除商品销售方式索引
                String saleStatusIndexKey = GOODS_SALE_STATUS_INDEX_KEY_PREFIX + goods.getGoodSaleStatus();
                connection.sRem(saleStatusIndexKey.getBytes(), String.valueOf(goodId).getBytes());

                // 6. 删除商品分类关联
                String goodsByTypeKey = GOODS_BY_TYPE_KEY_PREFIX + goods.getGoodTypeId();
                connection.sRem(goodsByTypeKey.getBytes(), String.valueOf(goodId).getBytes());

                // 7. 删除排序索引
                connection.zRem(GOODS_SORT_KEY.getBytes(), String.valueOf(goodId).getBytes());
            }

            return connection.exec();
        });
    }

    // ====================== 根据VO修改商品信息 ======================
    /**
     * 根据传入的 ProductInformationVO 修改 Redis 中对应商品的信息
     * @param productVO 商品信息载体
     */
    public void updateGoodsByVO(ProductInformationVO productVO) {
        if (productVO == null || productVO.getGoodId() == 0) {
            return;
        }
        long goodId = productVO.getGoodId();
        String goodsKey = GOODS_KEY_PREFIX + goodId;

        // 获取 Hash 操作对象
        HashOperations<String, String, Object> hashOps = redisTemplate.opsForHash();

        // 获取商品当前信息
        Map<String, Object> currentGoodsMap = hashOps.entries(goodsKey);
        if (currentGoodsMap.isEmpty()) {
            return; // 商品不存在，无需修改
        }

        // 将 VO 中的属性转换为 Map 键值对，用于更新 Redis Hash
        Map<String, Object> updateMap = convertVOToMap(productVO);

        // 先更新商品主数据（Redis Hash）
        hashOps.putAll(goodsKey, updateMap);

        // 获取修改前的商品信息（注意类型转换）
        Goods oldGoods = convertMapToGoods(new HashMap<>(currentGoodsMap));
        // 获取修改后的商品信息
        Goods newGoods = convertMapToGoods(new HashMap<>(hashOps.entries(goodsKey)));

        // 更新商品名称索引
        updateNameIndex(oldGoods, newGoods);
        // 更新商品状态索引
        updateStatusIndex(oldGoods, newGoods);
        // 更新商品销售方式索引
        updateSaleStatusIndex(oldGoods, newGoods);
        // 商品分类关联一般不随商品信息修改而直接变更（若需变更，需额外处理分类关联逻辑）
        // 排序索引基于时间，若修改不涉及重新排序，一般无需更新（若有特殊排序规则，可按需调整）
    }

    /**
     * 将 ProductInformationVO 转换为 Map，用于更新 Redis Hash
     */
    private Map<String, Object> convertVOToMap(ProductInformationVO productVO) {
        Map<String, Object> map = new HashMap<>();
        map.put("goodId", productVO.getGoodId());
        map.put("goodName", productVO.getGoodName());
        map.put("goodStatus", productVO.getGoodStatus());
        map.put("goodSaleStatus", productVO.getGoodSaleStatus());
        map.put("goodSale", productVO.getGoodSale());
        map.put("goodVirtualSale", productVO.getGoodVirtualSale());
        map.put("goodPrice", productVO.getGoodPrice());
        map.put("goodNum", productVO.getGoodNum());
        map.put("goodDescription", productVO.getGoodDescription());
        map.put("goodTypeId", productVO.getGoodTypeId());
        // 若 VO 中还有其他字段，如 goodIcon、goodMerId 等，也需在此添加
        return map;
    }

    /**
     * 更新商品名称索引
     */
    private void updateNameIndex(Goods oldGoods, Goods newGoods) {
        if (!Objects.equals(oldGoods.getGoodName(), newGoods.getGoodName())) {
            String oldNameIndexKey = GOODS_NAME_INDEX_KEY_PREFIX + oldGoods.getGoodName();
            redisTemplate.opsForSet().remove(oldNameIndexKey, oldGoods.getGoodId());

            String newNameIndexKey = GOODS_NAME_INDEX_KEY_PREFIX + newGoods.getGoodName();
            redisTemplate.opsForSet().add(newNameIndexKey, newGoods.getGoodId());
        }
    }

    /**
     * 更新商品状态索引
     */
    private void updateStatusIndex(Goods oldGoods, Goods newGoods) {
        if (!Objects.equals(oldGoods.getGoodStatus(), newGoods.getGoodStatus())) {
            String oldStatusIndexKey = GOODS_STATUS_INDEX_KEY_PREFIX + oldGoods.getGoodStatus();
            redisTemplate.opsForSet().remove(oldStatusIndexKey, oldGoods.getGoodId());

            String newStatusIndexKey = GOODS_STATUS_INDEX_KEY_PREFIX + newGoods.getGoodStatus();
            redisTemplate.opsForSet().add(newStatusIndexKey, newGoods.getGoodId());
        }
    }

    /**
     * 更新商品销售方式索引
     */
    private void updateSaleStatusIndex(Goods oldGoods, Goods newGoods) {
        if (!Objects.equals(oldGoods.getGoodSaleStatus(), newGoods.getGoodSaleStatus())) {
            String oldSaleIndexKey = GOODS_SALE_STATUS_INDEX_KEY_PREFIX + oldGoods.getGoodSaleStatus();
            redisTemplate.opsForSet().remove(oldSaleIndexKey, oldGoods.getGoodId());

            String newSaleIndexKey = GOODS_SALE_STATUS_INDEX_KEY_PREFIX + newGoods.getGoodSaleStatus();
            redisTemplate.opsForSet().add(newSaleIndexKey, newGoods.getGoodId());
        }
    }

    /**
     * 查询商品详情：根据商品 ID 从 Redis Hash 中拿数据并转换为 Goods 对象
     */
    private List<Goods> queryGoodsDetails(List<Integer> goodIds) {
        List<Goods> goodsList = new ArrayList<>();
        for (Integer goodId : goodIds) {
            String goodsKey = GOODS_KEY_PREFIX + goodId;
            Map<Object, Object> hashMap = redisTemplate.opsForHash().entries(goodsKey);
            goodsList.add(convertMapToGoods(hashMap));
        }
        return goodsList;
    }


    // ====================== 类型转换方法 ======================
    /**
     * 将 Set<Object> 转换为 Set<Integer>（支持 String/Integer 类型）
     */
    private Set<Integer> convertToIntegerSet(Set<Object> objects) {
        return objects.stream()
                .map(this::convertToInteger)
                .collect(Collectors.toSet());
    }

    /**
     * 将 Object 转换为 Integer（支持 String/Integer 类型，含异常处理）
     */
    private Integer convertToInteger(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof Integer) {
            return (Integer) obj;
        }
        if (obj instanceof String) {
            try {
                return Integer.parseInt((String) obj);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("无法将字符串转换为整数: " + obj, e);
            }
        }
        throw new IllegalArgumentException("不支持的类型转换，期望 Integer 或 String，但实际是: " + obj.getClass());
    }

    // ====================== 对象与 Map 互转方法 ======================
    /**
     * Goods 对象转 Map（用于存入 Redis Hash）
     */
    private Map<String, Object> convertGoodsToMap(Goods goods) {
        Map<String, Object> map = new HashMap<>();
        map.put("goodId", goods.getGoodId());
        map.put("goodName", goods.getGoodName());
        map.put("goodStatus", goods.getGoodStatus());
        map.put("goodSaleStatus", goods.getGoodSaleStatus());
        map.put("goodSale", goods.getGoodSale());
        map.put("goodVirtualSale", goods.getGoodVirtualSale());
        map.put("goodPrice", goods.getGoodPrice());
        map.put("goodIcon", goods.getGoodIcon());
        map.put("goodMerId", goods.getGoodMerId());
        map.put("goodNum", goods.getGoodNum());
        map.put("goodDescribe", goods.getGoodDescription());
        map.put("goodTypeId", goods.getGoodTypeId());
        return map;
    }

    /**
     * Map 转 Goods 对象（从 Redis Hash 中取出数据时用）
     */
    private Goods convertMapToGoods(Map<Object, Object> map) {
        Goods goods = new Goods();
        // 处理 Integer 类型字段
        goods.setGoodId(convertToInteger(map.get("goodId")));
        goods.setGoodStatus(convertToInteger(map.get("goodStatus")));
        goods.setGoodSaleStatus(convertToInteger(map.get("goodSaleStatus")));
        goods.setGoodSale(convertToInteger(map.get("goodSale")));
        goods.setGoodVirtualSale(convertToInteger(map.get("goodVirtualSale")));
        goods.setGoodMerId(convertToInteger(map.get("goodMerId")));
        goods.setGoodNum(convertToInteger(map.get("goodNum")));
        goods.setGoodTypeId(convertToInteger(map.get("goodTypeId")));
        // 处理 String 类型字段
        goods.setGoodName((String) map.get("goodName"));
        goods.setGoodIcon((String) map.get("goodIcon"));
        goods.setGoodDescription((String) map.get("goodDescribe"));
        // 处理价格（兼容 String/Double）
        Object priceObj = map.get("goodPrice");
        if (priceObj instanceof String) {
            goods.setGoodPrice(Double.parseDouble((String) priceObj));
        } else if (priceObj instanceof Double) {
            goods.setGoodPrice((Double) priceObj);
        } else {
            throw new IllegalArgumentException("商品价格类型不支持: " + (priceObj != null ? priceObj.getClass() : "null"));
        }
        return goods;
    }

    /**
     * GoodsType 对象转 Map（用于存入 Redis Hash）
     */
    private Map<String, Object> convertGoodsTypeToMap(GoodsType goodsType) {
        Map<String, Object> map = new HashMap<>();
        map.put("goodTypeId", goodsType.getGoodTypeId());
        map.put("goodTypeName", goodsType.getGoodTypeName());
        map.put("goodTypeMerId", goodsType.getGoodTypeMerId());
        map.put("goodTypeStatus", goodsType.getGoodTypeStatus());
        return map;
    }

    /**
     * Map 转 GoodsType 对象（从 Redis Hash 中取出数据时用）
     */
    private GoodsType convertMapToGoodsType(Map<Object, Object> map) {
        GoodsType goodsType = new GoodsType();
        // 处理 Integer 类型字段
        goodsType.setGoodTypeId(convertToInteger(map.get("goodTypeId")));
        goodsType.setGoodTypeMerId(convertToInteger(map.get("goodTypeMerId")));
        goodsType.setGoodTypeStatus(convertToInteger(map.get("goodTypeStatus")));
        // 处理 String 类型字段
        goodsType.setGoodTypeName((String) map.get("goodTypeName"));
        return goodsType;
    }
}